#include <iostream>
#include <sstream>

/* __________________________ SML library ________ */
#include "../inc/segment.h"
#include "../inc/trackball.h"
#include "../inc/segmenttree.h"
#include "../inc/link.h"
#include "../inc/brain.h"

/* ___________________ GLUT & OpenGL Librairies __ */
#ifdef __APPLE__
        #include <OpenGL/gl.h>
        #include <OpenGL/glu.h>
        #include <GLUT/glut.h>
#else
        #ifdef _WIN32
        #include "../glut.h"
        #else
        #include <GL/gl.h>
        #include <GL/glu.h>
        #include <GL/glut.h>
        #endif
#endif

using namespace std;

#define KEYBOARD_NULL 0
#define KEYBOARD_SAVE 1

/* ************************************************************************ */
/* ***						  GLOBALS VARIABLES                  		*** */
/* ************************************************************************ */

int		__winX = 500;											/* Window width. */
int		__winY = 500;											/* Window height. */
int		__displayMeshMode = VERTICES;							/* Displaying mode for meshes. Changed by user with the keyboard callback. */

int		__winID1;												/* Identity of the first window. */
int		__winID2;												/* Identity of the second window. */

TrackBall		__trackBall;									/* Trackball. Tool to rotate the objects. */

Mesh			__meshSource;									/* Surface of the source brain. */
Map				__mapSource;									/* Feature map of the source brain. */
SegmentTree*	__segTreeSource = new SegmentTree();			/* Tree containing the sulcis of the source brain : this root and each of its brothers represent one sulci. */

Mesh			__meshTarget;									/* Surface of the target brain. */
Map				__mapTarget;									/* Feature map of the target brain. */
SegmentTree*	__segTreeTarget = new SegmentTree();			/* Tree containing the sulcis of the target brain : this root and each of its brothers represent one sulci. */

SegmentTree*	__pickedSeg = NULL;

vector<Link>	__linkBBoxX;									/* Set of link array computed with the BBox similarity criteria. */
vector<Link>	__linkBBoxY;									/* '' */
vector<Link>	__linkBBoxZ;									/* '' */

vector<Link>	__linkBBoxBotX;									/* Set of link array computed with the BBox bot point similarity criteria. */
vector<Link>	__linkBBoxBotY;									/* '' */
vector<Link>	__linkBBoxBotZ;									/* '' */

vector<Link>	__linkBBoxTopX;									/* Set of link array computed with the BBox top point similarity criteria. */
vector<Link>	__linkBBoxTopY;									/* '' */
vector<Link>	__linkBBoxTopZ;									/* '' */

vector<Link>	__linkDepth;									/* Link array computed with the depth similarity criteria. */
vector<Link>	__linkArea;										/* Link array computed with the area similarity criteria. */
vector<Link>	__linkIntersection;								/* Link array computed with the intersection criteria. */
vector<Link>	__linkDistance;									/* Link array computed with the distance criteria. */

Brain			__brainSource;									/* Source brain. */
Brain			__brainTarget;									/* Target brain. */

int				__mapNbSegments = 10;							/* Number of segment we want to segment the map. */
int				__sulcisThresh = -20;							/* Threshod of depth to consider a segment as a sulcus. */
float			__segTreeThresh = 0.3;							/* Size (number of vertices <== HAS TO BE CHANGED !) minimum for an element (sulcus/gyrus) to be cosidered as relevant. */
int				__regroupThresh = 10;							/* Threshold for the method regrouping the different link arrays computed. */

int				__threshBBoxX = 5;
int				__threshBBox = 5;
int				__threshBBoxZ = 5;
int				__threshBBoxTopX = 5;
int				__threshBBoxTopY = 5;
int				__threshBBoxTopZ = 5;
int				__threshBBoxBotX = 5;
int				__threshBBoxBotY = 5;
int				__threshBBoxBotZ = 5;
int				__threshDepth = 0;
float			__threshArea = 0.1;
int				__threshDistance = 5;

int				__weightBBoxX = 3;
int				__weightBBoxY = 3;
int				__weightBBoxZ = 3;
int				__weightBBoxTopX = 2;
int				__weightBBoxTopY = 2;
int				__weightBBoxTopZ = 2;
int				__weightBBoxBotX = 2;
int				__weightBBoxBotY = 2;
int				__weightBBoxBotZ = 2;
int				__weightDepth = 1;
int				__weightArea = 1;
int				__weightDistance = 10;
int				__weightIntersection = 4;

string			__pathSave;
int				__keyboardMode = KEYBOARD_NULL;

/* ************************************************************************ */
/* ***						FUNCTIONS PROTOTYPES                  		*** */
/* ************************************************************************ */

string	float2string	(float f);
string	getExtension	(string _s);
void	displayString	( string _s, int _x, int _y, float _r = 1, float _g = 1, float _b = 0 );
void	redisplayBoth	();										/* Redisplay the two created windows. */
void	displayGL		();										/* GLUT callback for rendering. */
void	displayGL2		();										/* GLUT callback for rendering. */
void	reshapeGL		( int _w, int _h );						/* GLUT callback for resizing the window. */
void	initGL			();										/* GLUT OpenGL rendering initialization. */
void	keyboardGL		( unsigned char _k, int _x, int _y );	/* GLUT callback for keyboard typing. */
int		main			( int _argc, char** _argv );			/* Main function, launches the glut loop. */

/* ************************************************************************ */
/* ***						  MAIN PROGRAM								*** */
/* ************************************************************************ */

string float2string(float f)
{
	ostringstream os;
	os << f;
	return os.str();
}

void displayString(string _s, int _x, int _y, float _r, float _g, float _b)
{
	/* ___________________________________________________________ Set the display mode to a 2D drawing. _____ */
	glMatrixMode(GL_PROJECTION);
	glPushMatrix();
	glLoadIdentity();
	gluOrtho2D(0,__winX,0,__winY);
	glMatrixMode(GL_MODELVIEW);
	glDisable( GL_LIGHTING );
	glPushMatrix();
	glLoadIdentity();
	/* _______________________________________________________________________________________________________ */
	
	/* We then display the string in color. */
	glColor3f( _r, _g, _b );
	for ( int j = 0 ; j < (int)_s.size() ; j++ )
	{
		glRasterPos2i(  _x + (j*8) , _y );
		glutBitmapCharacter(GLUT_BITMAP_8_BY_13, (int)_s[j] );
	}	
	
	/* ___________________________________________________ Reset the display mode to a 3D scene drawing. _____ */
	glPopMatrix();
	glEnable( GL_LIGHTING );
	glMatrixMode(GL_PROJECTION);
	glPopMatrix();
	glMatrixMode(GL_MODELVIEW);
	/* _______________________________________________________________________________________________________ */
}

string getExtension(string _s)
{
	size_t posPoint;
	posPoint = _s.find_last_of(".");
	return _s.substr( posPoint );
}

void keyboardManagement(unsigned char _k, int& _mode)
{
	switch ( _mode )
	{
		case KEYBOARD_NULL :			
			if ( _k == 's' || _k == 'S' )
			{
				__pathSave.clear();
				_mode = KEYBOARD_SAVE;
			}
			
			if ( _k == 27 || _k == 'q' || _k == 'Q' )
				exit(0);
			
			if ( _k == 'i' || _k == 'I' )
				__brainSource.improveLinks( __brainTarget );
			
			if ( _k == '1' )
				__displayMeshMode = VERTICES;
			
			if ( _k == '2' )
				__displayMeshMode = EDGES;
			
			if ( _k == '3' )
				__displayMeshMode = FACES;
			
			if ( _k == '0' )
				__displayMeshMode = SMOOTH;
			
			break;
			
		case KEYBOARD_SAVE :
			if ( _k == 13 /* Enter touch. */ )
			{
				/* I did not write any const method so... */
				__brainSource.save( const_cast<char *> (__pathSave.c_str()) );
				__keyboardMode = KEYBOARD_NULL;
			}
			
			else
			{
				if ( _k == 8 /* Backspace. */ )
				{
					if ( __pathSave.size() > 0 )
						__pathSave.erase( __pathSave.end()-1 );
				}
				
				else
					__pathSave.push_back( _k );
			}
			break;
			
		default :
			break;
	}
}

void displayContext(int _mode)
{
	switch ( _mode )
	{		
		case KEYBOARD_SAVE :
			displayString("Save as :", 10, 40 );
			displayString( __pathSave, 10, 20 );
			break;
			
		case KEYBOARD_NULL :
			if ( __pickedSeg == NULL )
			{
				displayString("To get informations about a sulcus, right click on it.", 10, 20 );
				displayString( "s -> Save the brain. Expected format : .brn", 10, 40);
			}
			
			else
			{
				displayString( "Name : "+__pickedSeg->getName(), 10, __winY - 20 );
				displayString( "Color : "+float2string(__pickedSeg->getColor().getX())+" "+float2string(__pickedSeg->getColor().getY())+" "+float2string(__pickedSeg->getColor().getZ()), 10, __winY - 40 );
			}
			
			break;
			
		default :
			break;
	}
}

void redisplayBoth()
{
	if ( glutGetWindow() == __winID1 )
	{
		glutSetWindow( __winID2 );
		glutPostRedisplay();
		glutSetWindow( __winID1 );
	}
	
	else
	{
		glutSetWindow( __winID1 );
		glutPostRedisplay();
		glutSetWindow( __winID2 );
	}
	
	glutPostRedisplay();
}

void displayGL ()
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	__trackBall.displayBeginGL_GLUT();
	
		__brainSource.displaySurface( __displayMeshMode  );
		__brainSource.displayLinkReferences();
		
		/* If a sulci has been selected, we highlight it in white. */
		if ( __pickedSeg != NULL )
			__pickedSeg->display( OTHER_COLOR, 1,1,1 );
		
	__trackBall.displayEndGL_GLUT();
	
	displayContext( __keyboardMode );
	
	glutSwapBuffers();
}

void displayGL2 ()
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	__trackBall.displayBeginGL_GLUT();
	
		__brainTarget.displaySurface( __displayMeshMode, 1,1,1 );
		__brainSource.displayLinkMatched();
				
	__trackBall.displayEndGL_GLUT();
	glutSwapBuffers();
}

void reshapeGL(int _w, int _h)
{
       __winX = _w;
       __winY = _h;

        glViewport(0, 0,__winX,__winY);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();

        gluPerspective(60.0, (GLfloat)_w/(GLfloat)_h, 0.1, 500.0);

        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
		gluLookAt( -1.5, 0, 0,
				   0, 0, 0,
				   0, 0, 1 );
        
        redisplayBoth();
}

void keyboardGL(unsigned char _k, int _x, int _y)
{
	keyboardManagement( _k, __keyboardMode );
	
	redisplayBoth();
}

void specialKeyboardGL(int _k, int _x, int _y)
{
	if ( _k == GLUT_KEY_UP )
	{
		;
	}
	
	if ( _k == GLUT_KEY_DOWN )
	{
		;
	}
	
	if ( _k == GLUT_KEY_RIGHT )
	{
		;
	}
	
	if ( _k == GLUT_KEY_LEFT )
	{
		;
	}
	
	redisplayBoth();
}

void mouseGL (int _button, int _state, int _x, int _y)
{
	__trackBall.mouseGL_GLUT( GLUT_LEFT_BUTTON, _button, _state, _x, _y );
	
	if ( _button == GLUT_RIGHT_BUTTON && _state == GLUT_DOWN )
	{
		if ( glutGetWindow() == __winID1 )
			/*__pickedSeg = __brainSource.pickingLinkReference( _x, _y, &__trackBall );*/
			__pickedSeg = __brainSource.pickingNode( _x, _y, SULCIS, &__trackBall );
	}

	redisplayBoth();
}

void motionGL (int _x, int _y)
{
	__trackBall.motionGL_GLUT( _x, _y );
	redisplayBoth();
}

void initGL()
{
        GLfloat mat_specular   [4] = { 0.18, 0.18, 0.18, 0.18 };
        GLfloat mat_shininess  [ ] = { 128 };
        GLfloat global_ambient [ ] = { 0.02, 0.02, 0.05, 0.05 };
        GLfloat light0_ambient [ ] = { 0, 0, 0, 0 };
        GLfloat light0_diffuse [ ] = { 0.85, 0.85, 0.8, 0.85 };
        GLfloat light0_specular[ ] = { 0.85, 0.85, 0.15, 0.85 };

        glClearColor(0,0,0,0);

		glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
		glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
		glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess);
		
		glLightfv(GL_LIGHT0, GL_AMBIENT, light0_ambient);
		glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse);
		glLightfv(GL_LIGHT0, GL_SPECULAR, light0_specular);
		glLightModelfv(GL_LIGHT_MODEL_AMBIENT, global_ambient);
		
		glEnable(GL_LIGHTING);
		glEnable(GL_LIGHT0);
		
		glEnable(GL_COLOR_MATERIAL);
		glEnable(GL_NORMALIZE);
		
		glEnable(GL_BLEND);
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		
		glEnable(GL_DEPTH_TEST);
		glDepthFunc(GL_LEQUAL);       
}

int main ( int _argc, char** _argv )
{
	string argNameSource;
	string argNameTarget;
	
	if ( _argc > 2 )
	{
		argNameSource = _argv[1];
		size_t posSource = argNameSource.find_last_of("/");
		if ( posSource != string::npos )
			argNameSource = "Source : "+argNameSource.substr( posSource+1 );
	}
	
	if ( _argc == 2 && ( strcmp( _argv[1], "-h" ) == 0 || strcmp( _argv[1], "-help" ) == 0 ) )
	{
		cout<<"*"<<endl;
		cout<<"* SuleX : sulcis extracting, matching and labeling"<<endl;
		cout<<"*"<<endl;
		cout<<"* How to :"<<endl;
		cout<<"*\t- source.obj : mesh supporting the source brain"<<endl;
		cout<<"*\t- source.txt : map paired with the source mesh"<<endl;
		cout<<"*\t- target.obj : mesh supporting the target brain"<<endl;
		cout<<"*\t- target.txt : map paired with the target mesh"<<endl;
		cout<<"*\t- target.brn : target brain saved as a .brn file"<<endl;
		cout<<"*"<<endl;
		cout<<"* Option :"<<endl;
		cout<<"*\t-thresh"<<endl;
		cout<<"*\t\tmapThresh : number of segments you want to divide the map values range"<<endl;
		cout<<"*\t\tdepthThresh: depth [-50,50] under which a segment of the map is considered as a sulcus"<<endl;
		cout<<"*\t\tsizeThresh : minimum size (per centage of the mesh area) to consider an element as a sulcus"<<endl;
		cout<<"*\t\tcriteriaThresh : threshold to regroup the different link arrays computed in one"<<endl;
		cout<<endl;
		cout<<"Usage : "<<_argv[0]<<" source.obj source.txt {target.obj target.txt | target.brn} [-thresh mapThresh depthThresh sizeThresh criteriaThresh]"<<endl;
		return 0;
	}
	
	if ( _argc < 4 )
	{
		/* Number of arguments incorect. */
		cout<<"Usage : "<<_argv[0]<<" source.obj source.txt {target.obj target.txt | target.brn} [-thresh mapThresh depthThresh sizeThresh criteriaThresh]"<<endl;
		return -1;
	}
	
	/* Testing the -thresh option at position 4 and 5. */
	if ( _argc > 4 && strcmp( _argv[4], "-thresh" ) == 0 )
	{
		if ( _argc != 9 )
		{
			cout<<"Not enough arguments"<<endl;
			cout<<"Usage : "<<_argv[0]<<" source.obj source.txt {target.obj target.txt | target.brn} [-thresh mapThresh depthThresh sizeThresh criteriaThresh]"<<endl;
			return -1;
		}
		
		__mapNbSegments = atoi(_argv[5]);
		__sulcisThresh = atoi( _argv[6]);
		__segTreeThresh = atof ( _argv[7]);
		__regroupThresh = atoi ( _argv[8]);
	}
	
	if ( _argc > 5 && strcmp( _argv[5], "-thresh" ) == 0 )
	{
		if ( _argc != 10 )
		{
			cout<<"Not enough arguments"<<endl;
			cout<<"Usage : "<<_argv[0]<<" source.obj source.txt {target.obj target.txt | target.brn} [-thresh mapThresh depthThresh sizeThresh criteriaThresh]"<<endl;
			return -1;
		}
		
		__mapNbSegments = atoi(_argv[6]);
		__sulcisThresh = atoi( _argv[7]);
		__segTreeThresh = atof ( _argv[8]);
		__regroupThresh = atoi ( _argv[9]);
	}
	
	/* Loadin the brains informations. */
	__meshSource.loadOBJ( _argv[1] );																/* Loading the source mesh. */
	__meshSource.computeNormals();																	/* Computing its normals. */
	__meshSource.normalize();																			/* Resize it to a unit length box. */
	__mapSource.load( _argv[2] );																	/* Load the source feature map. */
	
	__mapSource.increaseContrast( CUBE, 1 );

	__mapSource.segment( __mapNbSegments );															/* Segmentate the map in 10 segments (can be given in parameter). */
	__meshSource.colorFromMap( __mapSource );														/* Setting colors for each vertex of the mesh according to it's map value. */
	__segTreeSource->createFromMap( LESSER_EQUAL, __sulcisThresh, __meshSource, __mapSource );		/* Creating a tree containing the sulcis of the brain. */
//	__segTreeSource = SegmentTree::filterSize( __segTreeSource, __segTreeThresh );					/* Filtering the tree so that the non revelant sulcis are not taken in account. */
	__segTreeSource = SegmentTree::splitTooBigSegments( &__meshSource, __segTreeSource, 1.5 );		/* We filter the tree : the segments that are too small to be considered as a sulcus are deleted. */
	__segTreeSource = SegmentTree::filterArea( &__meshSource, __segTreeSource, __segTreeThresh );	/* If there are some too big segments, we replace it by its sons. */
	
	/* Creating the brains. */
	__brainSource.setMesh( &__meshSource );															/* Attaching a the source mesh to the source brain. */
	__brainSource.setMap( &__mapSource );															/* Attaching the source map to the source brain. */
	__brainSource.setSulcis( __segTreeSource );														/* Attaching the source sulcis tree to the source brain. */
	__brainSource.setGyris( NULL );																	/* Attaching the source gyris to the source brain. As we did not computed them, we set it to NULL. */

	/* Regrouping segmets that are not far one from another one. */
//	__brainSource.setSulcis( SegmentTree::morphologicalClosing( __brainSource.getSulcis(), __brainSource.getMesh(), 1 ) );
	__brainSource.regroupSulcis( 3 );
	
	if ( _argc == 4 || _argc == 9 )
	{
		argNameTarget = _argv[3];
		size_t posTarget = argNameTarget.find_last_of("/");
		if ( posTarget != string::npos )
			argNameTarget = "Target : "+argNameTarget.substr( posTarget+1 );
		
		__brainTarget.load( _argv[3] );
	}
		
	if ( _argc == 5 || _argc == 10 )
	{
		argNameTarget = _argv[3];
		size_t posTarget = argNameSource.find_last_of("/");
		if ( posTarget != string::npos )
			argNameTarget = "Target : "+argNameTarget.substr( posTarget+1 );
		
		__meshTarget.loadOBJ( _argv[3] );																/* Same thing for the target. */
		__meshTarget.computeNormals();																	/* '' */
		__meshTarget.normalize();																		/* '' */
		__mapTarget.load( _argv[4] );																	/* '' */
		
		__mapTarget.increaseContrast( CUBE, 1 );
		
		__mapTarget.segment( __mapNbSegments );															/* '' */
		__meshTarget.colorFromMap( __mapTarget );														/* '' */
		__segTreeTarget->createFromMap( LESSER_EQUAL, __sulcisThresh, __meshTarget, __mapTarget );		/* '' */
//		__segTreeTarget = SegmentTree::filterSize( __segTreeTarget, __segTreeThresh );					/* '' */
		
		__segTreeTarget = SegmentTree::splitTooBigSegments( &__meshTarget, __segTreeTarget, 1.5 );		/* If there are some too big segments, we replace it by its sons. */
		__segTreeTarget = SegmentTree::filterArea( &__meshTarget, __segTreeTarget, __segTreeThresh );	/* We filter the tree : the segments that are too small to be considered as a sulcus are deleted. */
		
//		/* Regrouping segmets that are not far one from another one. */
//		__brainTarget.setSulcis( SegmentTree::morphologicalClosing( __brainTarget.getSulcis(), __brainTarget.getMesh(), 1 ) );
		__brainTarget.regroupSulcis( 3 );
		
				
		__brainTarget.setMesh( &__meshTarget );															/* Same thing for the target brain. */
		__brainTarget.setMap( &__mapTarget );															/* '' */
		__brainTarget.setSulcis( __segTreeTarget );														/* '' */
		__brainTarget.setGyris( NULL );																	/* '' */
	
		/* Attaching one color per element (sulcis or gyris) in the target brain. */
		__brainTarget.colorElements();
	}

	/* Computing the links within several similarity criterias. */
	__linkBBoxX = __brainSource.linkBy_BBoxX( __brainTarget, __threshBBoxX );						/* Computing with a set of BBox criteria. */
	__linkBBoxY = __brainSource.linkBy_BBoxY( __brainTarget, __threshBBoxZ );						/* '' */
	__linkBBoxZ = __brainSource.linkBy_BBoxZ( __brainTarget, __threshBBoxZ );						/* '' */
	
	__linkBBoxBotX = __brainSource.linkBy_BBoxBotX( __brainTarget, __threshBBoxBotX );				/* Computing with a set of BBox bot point criteria. */
	__linkBBoxBotY = __brainSource.linkBy_BBoxBotY( __brainTarget, __threshBBoxBotY );				/* '' */
	__linkBBoxBotZ = __brainSource.linkBy_BBoxBotZ( __brainTarget, __threshBBoxBotZ );				/* '' */
	
	__linkBBoxTopX = __brainSource.linkBy_BBoxTopX( __brainTarget, __threshBBoxTopX );				/* Computing with a set of BBos top point criteria. */
	__linkBBoxTopY = __brainSource.linkBy_BBoxTopY( __brainTarget, __threshBBoxTopY );				/* '' */
	__linkBBoxTopZ = __brainSource.linkBy_BBoxTopZ( __brainTarget, __threshBBoxTopZ );				/* '' */
	
	__linkDepth = __brainSource.linkBy_Depth( __brainTarget, __threshDepth );						/* Computing with the depth criteria. */
	
	__linkArea = __brainSource.linkBy_Area( __brainTarget, __threshArea );							/* Computing with the area criteria. */
	
	__linkDistance = __brainSource.linkBy_Distance( __brainTarget, __threshDistance );				/* Computing with the distance criteria. */
	
	__linkIntersection = __brainSource.linkBy_Intersection( __brainTarget );						/* Computing with the intersection criteria. */

	/* Mixing all the criteria to create the final matching. */
	__brainSource.linkBy_Crtiteria( __regroupThresh,												/* Threshold */
									&__linkDistance, __weightDistance,								/* Link array and its weight. */
									&__linkIntersection, __weightIntersection,						/* '' */
									&__linkBBoxX, __weightBBoxX,									/* '' */
									&__linkBBoxY, __weightBBoxY,									/* '' */
									&__linkBBoxZ, __weightBBoxZ,									/* '' */
									&__linkBBoxBotX, __weightBBoxBotX,								/* '' */
									&__linkBBoxBotY, __weightBBoxBotY,								/* '' */
									&__linkBBoxBotZ, __weightBBoxBotZ,								/* '' */
									&__linkBBoxTopX, __weightBBoxTopX,								/* '' */
									&__linkBBoxTopY, __weightBBoxTopY,								/* '' */
									&__linkBBoxTopZ, __weightBBoxTopZ,								/* '' */
									&__linkDepth, __weightDepth,									/* '' */
									&__linkArea, __weightArea,										/* '' */
									NULL );															/* DON'T FORGET THE NULL PARAMETER TO END THE ARGUMENT LIST ! */
	
	/* ************************************************************************ */
	/* ***					CREATING WINDOW WITH GLUT						*** */
	/* ************************************************************************ */
	int posX, posY;
	
	glutInit(&_argc, _argv);
	
	posX = 250;
	posY = 200;
	
	glutInitWindowSize( __winX , __winY );
	glutInitWindowPosition(posX, posY);

	glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);	
	__winID1 = glutCreateWindow( argNameSource.c_str() );
	glutDisplayFunc(displayGL);
	glutReshapeFunc(reshapeGL);
	glutKeyboardFunc(keyboardGL);
	glutSpecialFunc(specialKeyboardGL);
	glutMouseFunc(mouseGL);
	glutMotionFunc(motionGL);
	initGL();
	
	/* _______________________________________________________________ Deuxieme fenetre _____ */
	glutInitWindowSize( __winX , __winY );
	glutInitWindowPosition(posX + __winX + 10, posY);

	glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);	
	__winID2 = glutCreateWindow( argNameTarget.c_str() );
	glutDisplayFunc(displayGL2);
	glutReshapeFunc(reshapeGL);
	glutKeyboardFunc(keyboardGL);
	glutSpecialFunc(specialKeyboardGL);
	glutMouseFunc(mouseGL);
	glutMotionFunc(motionGL);
	initGL();
	
	glutMainLoop();
	
	return 0;
}
